#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据处理GUI应用程序
基于PySide6和Qt6的桌面应用
"""

import sys
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                               QHBoxLayout, QLabel, QLineEdit, QPushButton, 
                               QFileDialog, QMessageBox, QRadioButton, QButtonGroup, QTextEdit, QDialog)
from PySide6.QtCore import Qt, QThread, Signal
from PySide6.QtGui import QFont, QIcon
import datetime
import threading
import os
from processPTC import processPTC
import importlib.util
import subprocess
from astropy.io import fits
import numpy as np
from getNoise import remove_overscan


class DataProcessingGUI(QMainWindow):
    """数据处理GUI主窗口"""
    
    def __init__(self):
        super().__init__()
        self.init_ui()
        
    def init_ui(self):
        """初始化用户界面"""
        # 设置窗口标题和大小
        self.setWindowTitle("CCD数据处理工具")
        self.setGeometry(100, 100, 900, 500)
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        main_h_layout = QHBoxLayout(central_widget)
        left_widget = QWidget()
        main_layout = QVBoxLayout(left_widget)
        main_layout.setSpacing(20)
        main_layout.setContentsMargins(30, 30, 30, 30)
        
        # 添加标题
        title_label = QLabel("CCD数据处理工具")
        title_label.setAlignment(Qt.AlignCenter)
        title_font = QFont()
        title_font.setPointSize(18)
        title_font.setBold(True)
        title_label.setFont(title_font)
        main_layout.addWidget(title_label)
        main_layout.addSpacing(20)
        
        # 单选按钮区域
        radio_layout = QHBoxLayout()
        radio_label = QLabel("选择CCD类型:")
        radio_label.setMinimumWidth(100)
        
        # 创建单选按钮组
        self.radio_group = QButtonGroup()
        self.radio_290_00 = QRadioButton("290-99")
        self.radio_47_20 = QRadioButton("47-20")
        
        # 将单选按钮添加到按钮组
        self.radio_group.addButton(self.radio_290_00)
        self.radio_group.addButton(self.radio_47_20)
        
        # 默认选择第一个选项
        self.radio_290_00.setChecked(True)
        
        radio_layout.addWidget(radio_label)
        radio_layout.addWidget(self.radio_290_00)
        radio_layout.addWidget(self.radio_47_20)
        radio_layout.addStretch()  
        
        main_layout.addLayout(radio_layout)
        
        main_layout.addSpacing(10)
        
        # 按钮区域
        buttons_layout1 = QHBoxLayout()
        buttons_layout1.setSpacing(15)
        buttons_layout2 = QHBoxLayout()
        buttons_layout2.setSpacing(15)
        # 第一行按钮
        self.process_button1 = QPushButton("PTC/PRC")
        self.process_button1.setMinimumHeight(40)
        self.process_button1.clicked.connect(self.process_action1)
        buttons_layout1.addWidget(self.process_button1)
        self.process_button2 = QPushButton("Bias/Noise")
        self.process_button2.setMinimumHeight(40)
        self.process_button2.clicked.connect(self.process_action2)
        buttons_layout1.addWidget(self.process_button2)
        # 第二行按钮
        self.process_button3 = QPushButton("Linearity")
        self.process_button3.setMinimumHeight(40)
        self.process_button3.clicked.connect(self.process_action3)
        buttons_layout2.addWidget(self.process_button3)
        self.process_button4 = QPushButton("过扫区修正")
        self.process_button4.setMinimumHeight(40)
        self.process_button4.clicked.connect(self.process_action4)
        buttons_layout2.addWidget(self.process_button4)
        main_layout.addLayout(buttons_layout1)
        main_layout.addLayout(buttons_layout2)
        
        main_layout.addStretch()
        # 右侧为日志框
        self.log_text_edit = QTextEdit()
        self.log_text_edit.setReadOnly(True)
        self.log_text_edit.setMinimumWidth(250)
        self.log_text_edit.setPlaceholderText("日志输出...")
        main_h_layout.addWidget(left_widget, stretch=3)
        main_h_layout.addWidget(self.log_text_edit, stretch=2)
        
    def browse_path(self, line_edit):
        """浏览文件夹对话框"""
        folder_path = QFileDialog.getExistingDirectory(
            self, 
            "选择文件夹",
            "",
            QFileDialog.ShowDirsOnly
        )
        if folder_path:
            line_edit.setText(folder_path)
    
    def get_selected_type(self):
        """获取当前选中的类型"""
        if self.radio_290_00.isChecked():
            return "290-99"
        elif self.radio_47_20.isChecked():
            return "47-20"
        else:
            return "未选择"
    
    def process_action1(self):
        """PTC/PRC处理按钮动作：弹出参数设置对话框"""
        dlg = PTCDialog(self)
        if dlg.exec() == QDialog.Accepted:
            fits_dir, out_base_dir = dlg.get_dirs()
            if not fits_dir or not out_base_dir:
                QMessageBox.warning(self, "警告", "请输入输入和输出目录！")
                return
            now_str = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            out_dir = os.path.join(out_base_dir, f"PTC_PRC_result_{now_str}")
            self.log_text_edit.append(f"开始PTC/PRC处理：\n输入目录: {fits_dir}\n输出目录: {out_dir}")
            self.ptc_worker = PTCWorker(fits_dir, out_dir)
            self.ptc_worker.finished_signal.connect(self.log_text_edit.append)
            self.ptc_worker.result_signal.connect(self.run_plot_prc)
            self.ptc_worker.start()

    def process_action2(self):
        """Bias/Noise按钮动作：弹出参数设置对话框"""
        dlg = NoiseDialog(self)
        if dlg.exec() == QDialog.Accepted:
            fits_path, out_dir = dlg.get_paths()
            if not fits_path:
                QMessageBox.warning(self, "警告", "请输入FITS文件路径！")
                return
            # 如果输出目录为空，默认在输入文件同目录下
            if not out_dir:
                out_dir = os.path.dirname(fits_path)
            self.log_text_edit.append(f"开始噪声分析：\n输入文件: {fits_path}\n输出目录: {out_dir}")
            self.noise_worker = NoiseWorker(fits_path, out_dir)
            self.noise_worker.log_signal.connect(self.log_text_edit.append)
            self.noise_worker.finished_signal.connect(self.log_text_edit.append)
            self.noise_worker.start()
    
    def process_action3(self):
        """线性度按钮动作（待实现）"""
        QMessageBox.information(self, "信息", "线性度按钮被点击，功能待实现。")

    def process_action4(self):
        """过扫区修正按钮动作"""
        dlg = OverscanDialog(self)
        if dlg.exec() == QDialog.Accepted:
            file_path, out_dir = dlg.get_paths()
            if not file_path:
                QMessageBox.warning(self, "警告", "请输入FITS文件路径！")
                return
            import os
            if not out_dir:
                out_dir = os.path.dirname(file_path)
            base_name = os.path.basename(file_path)
            name, ext = os.path.splitext(base_name)
            out_file = os.path.join(out_dir, f"{name}_overscan{ext}")
            # 读取FITS数据
            try:
                with fits.open(file_path) as hdul:
                    imgdata = hdul[0].data.astype(float)
                    header = hdul[0].header
            except Exception as e:
                QMessageBox.critical(self, "错误", f"读取FITS文件失败：{e}")
                return
            # 过扫区修正
            try:
                self.log_text_edit.append(f"开始修正过扫区...")
                img_corr = remove_overscan(imgdata)
            except Exception as e:
                QMessageBox.critical(self, "错误", f"过扫区修正失败：{e}")
                return
            # 保存修正后的数据
            try:
                fits.writeto(out_file, img_corr, header, overwrite=True)
                self.log_text_edit.append(f"修正后的FITS文件已保存：\n{out_file}")
            except Exception as e:
                QMessageBox.critical(self, "错误", f"保存FITS文件失败：{e}")

    def run_plot_prc(self, out_dir):
        try:
            import importlib.util
            plot_prc_path = os.path.join(os.path.dirname(__file__), 'plot_prc.py')
            spec = importlib.util.spec_from_file_location("plot_prc", plot_prc_path)
            plot_prc = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(plot_prc)
            plot_prc.plotPRC(out_dir)
            self.log_text_edit.append("绘图完成，所有结果已保存到输出文件夹！")
        except Exception as e:
            self.log_text_edit.append(f"绘图出错: {e}")


class PTCWorker(QThread):
    finished_signal = Signal(str)
    result_signal = Signal(str)

    def __init__(self, fits_dir, out_dir):
        super().__init__()
        self.fits_dir = fits_dir
        self.out_dir = out_dir

    def run(self):
        try:
            script_path = os.path.join(os.path.dirname(__file__), 'processPTC.py')
            cmd = [sys.executable, script_path, self.fits_dir, self.out_dir]
            process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
            for line in process.stdout:
                self.finished_signal.emit(line.rstrip())
            process.wait()
            if process.returncode == 0:
                self.result_signal.emit(self.out_dir)
                self.finished_signal.emit("PTC/PRC数据处理完成！")
            else:
                self.finished_signal.emit(f"PTC/PRC处理出错，返回码: {process.returncode}")
        except Exception as e:
            self.finished_signal.emit(f"处理出错: {e}")


class NoiseWorker(QThread):
    log_signal = Signal(str)
    finished_signal = Signal(str)
    def __init__(self, fits_path, out_dir):
        super().__init__()
        self.fits_path = fits_path
        self.out_dir = out_dir
    def run(self):
        try:
            script_path = os.path.join(os.path.dirname(__file__), 'getNoise.py')
            cmd = [sys.executable, script_path, self.fits_path, self.out_dir]
            process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
            for line in process.stdout:
                self.log_signal.emit(line.rstrip())
            process.wait()
            if process.returncode == 0:
                self.finished_signal.emit("噪声分析完成！")
            else:
                self.finished_signal.emit(f"噪声分析出错，返回码: {process.returncode}")
        except Exception as e:
            self.finished_signal.emit(f"噪声分析出错: {e}")


class PTCDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("PTC/PRC参数设置")
        self.setMinimumWidth(400)
        layout = QVBoxLayout()
        # 输入目录
        in_layout = QHBoxLayout()
        in_label = QLabel("输入目录:")
        self.in_edit = QLineEdit()
        in_browse = QPushButton("浏览")
        in_browse.clicked.connect(self.browse_in)
        in_layout.addWidget(in_label)
        in_layout.addWidget(self.in_edit)
        in_layout.addWidget(in_browse)
        layout.addLayout(in_layout)
        # 输出目录
        out_layout = QHBoxLayout()
        out_label = QLabel("输出目录:")
        self.out_edit = QLineEdit()
        out_browse = QPushButton("浏览")
        out_browse.clicked.connect(self.browse_out)
        out_layout.addWidget(out_label)
        out_layout.addWidget(self.out_edit)
        out_layout.addWidget(out_browse)
        layout.addLayout(out_layout)
        # 开始处理按钮
        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.start_btn = QPushButton("开始处理")
        self.start_btn.clicked.connect(self.accept)
        btn_layout.addWidget(self.start_btn)
        layout.addLayout(btn_layout)
        self.setLayout(layout)
    def browse_in(self):
        dir_path = QFileDialog.getExistingDirectory(self, "选择输入文件目录")
        if dir_path:
            self.in_edit.setText(dir_path)
    def browse_out(self):
        dir_path = QFileDialog.getExistingDirectory(self, "选择输出目录")
        if dir_path:
            self.out_edit.setText(dir_path)
    def get_dirs(self):
        return self.in_edit.text().strip(), self.out_edit.text().strip()


class NoiseDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Bias/Noise参数设置")
        self.setMinimumWidth(400)
        layout = QVBoxLayout()
        # 输入文件
        in_layout = QHBoxLayout()
        in_label = QLabel("输入FITS文件:")
        self.in_edit = QLineEdit()
        in_browse = QPushButton("浏览")
        in_browse.clicked.connect(self.browse_in)
        in_layout.addWidget(in_label)
        in_layout.addWidget(self.in_edit)
        in_layout.addWidget(in_browse)
        layout.addLayout(in_layout)
        # 输出目录
        out_layout = QHBoxLayout()
        out_label = QLabel("输出目录:")
        self.out_edit = QLineEdit()
        out_browse = QPushButton("浏览")
        out_browse.clicked.connect(self.browse_out)
        out_layout.addWidget(out_label)
        out_layout.addWidget(self.out_edit)
        out_layout.addWidget(out_browse)
        layout.addLayout(out_layout)
        # 开始处理按钮
        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.start_btn = QPushButton("开始处理")
        self.start_btn.clicked.connect(self.accept)
        btn_layout.addWidget(self.start_btn)
        layout.addLayout(btn_layout)
        self.setLayout(layout)
    def browse_in(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "选择FITS文件", "", "FITS Files (*.fits);;All Files (*)")
        if file_path:
            self.in_edit.setText(file_path)
    def browse_out(self):
        dir_path = QFileDialog.getExistingDirectory(self, "选择输出目录")
        if dir_path:
            self.out_edit.setText(dir_path)
    def get_paths(self):
        return self.in_edit.text().strip(), self.out_edit.text().strip()


class OverscanDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("过扫区修正参数设置")
        self.setMinimumWidth(400)
        layout = QVBoxLayout()
        # 输入文件
        in_layout = QHBoxLayout()
        in_label = QLabel("输入FITS文件:")
        self.in_edit = QLineEdit()
        in_browse = QPushButton("浏览")
        in_browse.clicked.connect(self.browse_in)
        in_layout.addWidget(in_label)
        in_layout.addWidget(self.in_edit)
        in_layout.addWidget(in_browse)
        layout.addLayout(in_layout)
        # 输出目录
        out_layout = QHBoxLayout()
        out_label = QLabel("输出目录:")
        self.out_edit = QLineEdit()
        out_browse = QPushButton("浏览")
        out_browse.clicked.connect(self.browse_out)
        out_layout.addWidget(out_label)
        out_layout.addWidget(self.out_edit)
        out_layout.addWidget(out_browse)
        layout.addLayout(out_layout)
        # 开始处理按钮
        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.start_btn = QPushButton("开始处理")
        self.start_btn.clicked.connect(self.accept)
        btn_layout.addWidget(self.start_btn)
        layout.addLayout(btn_layout)
        self.setLayout(layout)
    def browse_in(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "选择FITS文件", "", "FITS Files (*.fits *.fit)")
        if file_path:
            self.in_edit.setText(file_path)
    def browse_out(self):
        dir_path = QFileDialog.getExistingDirectory(self, "选择输出目录")
        if dir_path:
            self.out_edit.setText(dir_path)
    def get_paths(self):
        return self.in_edit.text().strip(), self.out_edit.text().strip()


def main():
    """主函数"""
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    window = DataProcessingGUI()
    window.show()
    sys.exit(app.exec())


if __name__ == "__main__":
    main() 